#include "MWImage.h"
#include "MWResourceManager.h"
#include "MWMath.h"

#include "stb_image_aug.h"

namespace Myway {

	MImage::MImage()
		: mWidth(0)
		, mHeight(0)
		, mColorData(0)
	{
	}

	MImage::~MImage()
	{
		Destroy();
	}

	void MImage::Create(int width, int height)
	{
		Destroy();

		mWidth = width;
		mHeight = height;

		mColorData = (Color *)malloc(mWidth * mHeight * 4);

		memset(mColorData, 0, mWidth * mHeight * sizeof(Color));
	}

	void MImage::Destroy()
	{
		if (mColorData)
			free (mColorData);

		mWidth = mHeight = 0;
	}

	bool MImage::LoadFromFile(const char * filename)
	{
		Destroy();

		DataStreamPtr stream = ResourceManager::Instance()->OpenResource(filename);

		return LoadFromStream(stream);
	}

	bool MImage::LoadFromStream(DataStreamPtr stream)
	{
		Destroy();

		if (stream == NULL)
			return false;

		mColorData = (Color * )rgba_load_from_stream(stream, mWidth, mHeight);

		return mColorData != NULL;
	}

	void MImage::SetColor(int x, int y, Color color)
	{
		d_assert (x < mWidth && y < mHeight);

		mColorData[y * mWidth + x] = color;
	}

	MImage::Color MImage::GetColor(int x, int y) const
	{
		d_assert (x < mWidth && y < mHeight);

		return mColorData[y * mWidth + x];
	}

	void MImage::ToPower2()
	{
		if (!mColorData || (Math::IsPower2(mWidth) && Math::IsPower2(mHeight)))
			return ;

		int w2 = 1, h2 = 1;

		while (w2 < mWidth)
			w2 *= 2;

		while (h2 < mHeight)
			h2 *= 2;

		Color * tcolor = new Color[w2 * h2];

		memset(tcolor, 0, sizeof(Color) * w2 * h2);

		Color * dest = tcolor;
		Color * src = mColorData;
		for (int i = 0; i < mHeight; ++i)
		{
			memcpy(dest, src, mWidth * sizeof(Color));

			dest += w2;
			src += mWidth;
		}

		Destroy();

		mWidth = w2;
		mHeight = h2;
		mColorData = tcolor;
	}

	void * rgba_load_from_stream(DataStreamPtr stream, int & width, int & height)
	{
		int channels = 0;

		unsigned char *result = stbi_load_from_memory(
			(const stbi_uc * )stream->GetData(), stream->Size(),
			&width, &height, &channels, 4);

		return result;
	}

	void rgba_free(void * _ptr)
	{
		if (_ptr)
			free(_ptr);
	}

}

